package _03_myInteger;

public final class MyInteger implements Comparable<Integer> {
    
    // 最小值常量，-2**31 = -2147483648
    public static final int MIN_VALUE = 0x80000000;
    // 最大值常数，2**31 = 2147483647
    public static final int MAX_VALUE = 0x7fffffff;
    
    private final int value;
    
    public MyInteger(int value) {
        this.value = value;
    }
    
    // 由十进制整数字符s构造整数对象，构造方法只支持十进制，s包含正负号
    public MyInteger(String s) {
        this.value = MyInteger.parseInt(s, 10);
    }
    
    // 将radix进制数的串s转换为十进制整数，s指定整数的radix进行原码字符串，包含正负号，2 <= radix < 16
    // 默认十进制。若不能将s转换成整数，则抛出数值格式异常
    public static int parseInt(String s, int radix) throws NumberFormatException {
        // TODO Auto-generated method stub
        if (s == null) {
            throw new NumberFormatException("null");
        }
        if (radix < 2 || radix > 16) {
            throw new NumberFormatException("radix = " + radix + ", 进制超出2 ~ 16的范围。");
        }
        int value = 0;
        int i = 0;
        // 符号位，记住正负号
        int sign = s.charAt(0) == '-' ? -1 : 1;
        if (s.charAt(0) == '+' || s.charAt(0) == '-') {
            i++;
            if (s.length() == 1) {
                throw new NumberFormatException("\"" + s + "\"");
            }
        }
        // 222五进制转十进制：2 * 5**2 + 2 * 5**1 + 2 * 5**0 = 2 * 25 + 2 * 5 + 2 * 1 = 50 + 10 + 2 = 62;
        while (i < s.length()) {
            char ch = s.charAt(i++);
            // 满足ch - '0' < radix，那么在这个条件下的算法不处理字母，只处理小于radix的整数，由于整数范围0~10，即使radix>10也是可以处理的
            if (ch >= '0' && ch - '0' < radix) {
                // 还是以("222"，5)为例：222 --> 0 * 5 + 2 = 2 --> 2 * 5 + 2 = 12 --> 12 * 5 + 2 == 62，这个算法和平常的算法不同，但也能得到结果
                value = value * radix + ch - '0';
            } else if (radix > 10 && radix <= 16 && ch >= 'a' && ch - 'a' < radix - 10) {
                value = value * radix + ch - 'a' + 10;
            } else if (radix > 10 && radix <= 16 && ch >= 'A' && ch - 'A' < radix - 10) {
                value = value * radix + ch - 'A' + 10;
            } else {
                throw new NumberFormatException(radix + "进制整数不能识别" + ch);
            }
        }
        return value * sign;
    }
    
    // 返回整数value的十六进制补码字符串。采用位运算
    public static String toHexString(int value) {
        // 一个int有8个十六进制位
        char[] buffer = new char[8];
        // 循环八次，高位补零
        for (int i = buffer.length - 1; i >= 0; i--) {
            // value & 15为移位运算，即value % 16，value除16取余
            int bit = value & 15;
            buffer[i] = (char) (bit <= 9 ? bit + '0' : bit + 'a' - 10);
            // value >>>= 4即value = value >>> 4，表示value右移二进制4位，即一个16进制位，高位补零，相当于value / 16
            value >>>= 4;
        }
        return new String(buffer);
    }
    
    // 返回整数value的二进制补码字符串。采用位运算
    public static String toBinaryString(int value) {
        // 一个int 有32个二进制位
        char[] buffer = new char[32];
        // 循环32次，高位补零
        for (int i = buffer.length - 1; i >= 0; i--) {
            // value % 2
            buffer[i] = (char) ((value & 1) + '0');
            // value右移二进制位1位，即value / 2
            value >>>= 1;
        }
        return new String(buffer);
    }
    
    // 返回整数value的八进制补码字符串。采用位运算
    public static String toOctalString(int value) {
        // 10位不够，需要加一位
        char[] buffer = new char[32/3 + 1];
        // 循环11次，高位补零
        for (int i = buffer.length - 1; i >= 0; i--) { 
            buffer[i] = (char) ((value & 7) + '0');
            value >>>= 3;
        }
        return new String(buffer);
    }

    // 返回整数value的radix进制原码字符串，有符号，高位补0；radix取值为2、4、8、10、16。采用移位运算（除radix取余法）
    public static String toString(int value, int radix) {
        if (radix == 10) {
            return value + "";
        }
        if (radix == 2 || radix == 4 || radix == 8 || radix == 16) {
            int n = 0;
            for (int i = radix - 1; i > 0; i >>>= 1) {
                n++;
            }
            // 32.0/3 + 1.5 = 10.6 + 0.5 (int)= 11，而其它进制都能整除，+0.5还是本身，+1是符号位
            char[] buffer = new char[(int) (32.0/n + 0.5 + 1)];
            buffer[0] = '+';
            if (value < 0) {
                buffer[0] = '-';
                if (value != MIN_VALUE) {
                    value = -value;
                }
            }
            for (int i = buffer.length - 1; i > 0; i--) {
                int bit = value & (radix - 1);
                buffer[i] = (char) (bit <= 9 ? bit + '0' : bit + 'a' - 10);
                value >>>= n;
            }
            return new String(buffer);
        }
        // 无效参数异常
        throw new IllegalArgumentException("radix参数值" + radix + "表示的进制无效。");
    }
    
    @Override
    public int compareTo(Integer o) {
        // TODO Auto-generated method stub
        return 0;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("测试parseInt(String, int)方法：");
        System.out.println(parseInt("222", 5) + ", " + parseInt("222", 16)
        + ", " + MyInteger.parseInt("Aae", 16));
        // System.out.println(MyInteger.parseInt("555", 5));
        // System.out.println(MyInteger.parseInt("bbb", 11));
        System.out.println("测试toHexString(int)方法：");
        System.out.println(toHexString(1026));
        System.out.println(toHexString(MIN_VALUE));
        System.out.println(toHexString(-MIN_VALUE));
        System.out.println("测试toBinaryString(int)方法：");
        System.out.println(toBinaryString(1026));
        System.out.println(toBinaryString(-1026));
        System.out.println(toBinaryString(MIN_VALUE));
        System.out.println(toBinaryString(-MIN_VALUE));
        System.out.println(toBinaryString(MAX_VALUE));
        System.out.println(toBinaryString(-MAX_VALUE));
        System.out.println("测试toOctalString(int)方法：");
        System.out.println(toOctalString(1026));
        System.out.println(toOctalString(MIN_VALUE));
        System.out.println("测试toString(int, int)方法：");
        System.out.println(toString(4050, 16));
        System.out.println(toString(MAX_VALUE, 16));
        System.out.println(toString(-MIN_VALUE, 16));
        System.out.println(toString(-1026, 16));
    }

    

}
